﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Xml;

namespace PrintUnit
{
    class XMLmodle
    {
        /// <summary>
        /// 页面宽度
        /// </summary>
        private float pageWidth = 0;

        /// <summary>
        /// 页面高度
        /// </summary>
        private float pageHeight = 0;

        /// <summary>
        /// 画家对象
        /// </summary>
        private Graphics graphics;

        private float oldAddHeight = 0;

        private List<Bitmap> bitmapList;

        public XMLmodle()
        {

        }

        public XMLmodle(Graphics graphics)
        {
            this.graphics = graphics;
        }

        public void SetMsg<T>(string url, List<T> saleList, dynamic paramArray, Size size, ref List<Bitmap> bitmapList)
        {
            pageHeight = size.Height;
            pageWidth = size.Width;
            this.bitmapList = bitmapList;
            Bitmap bitmap = new Bitmap(size.Width, size.Height);
            bitmapList.Add(bitmap);
            graphics = Graphics.FromImage(bitmap);
            //graphics.DrawImage(bitmap,0,0);
            GetPagePrintSize(bitmap);
            XmlDocument xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(url);
            }
            catch (FileNotFoundException e)
            {
                throw e;
            }
            XmlNode rootNode = xmlDoc.SelectSingleNode("Page");
            XmlNode PageNode = rootNode.SelectSingleNode("Head");
            int lengths = 0;
            PrintHead(PageNode, paramArray, ref lengths);
            XmlNode BodyNode = rootNode.SelectSingleNode("Body");
            PrintBody(BodyNode, saleList, ref lengths);
            XmlNode FootNode = rootNode.SelectSingleNode("Foot");
            PrintFoot(FootNode, paramArray, ref lengths);
        }

        private void PrintHead(XmlNode pageNode, dynamic paramArray, ref int lengths)
        {
            //设置字体颜色
            Brush b = new SolidBrush(Color.Black);
            foreach (XmlNode TextNode in pageNode.ChildNodes)
            {
                XmlElement x1 = TextNode as XmlElement;
                string name = x1.GetAttribute("Name");
                int x = Convert.ToInt32(x1.GetAttribute("X"));
                int y = Convert.ToInt32(x1.GetAttribute("Y"));
                int fontSize = Convert.ToInt32(x1.GetAttribute("FontSize"));
                bool bold = Convert.ToBoolean(x1.GetAttribute("Bold"));
                var underLine = x1.GetAttribute("UnderLine");
                bool center = Convert.ToBoolean(x1.GetAttribute("Center"));
                bool newLine = Convert.ToBoolean(x1.GetAttribute("NewLine"));
                var value = x1.GetAttribute("Value");
                //设置字体样式
                Font f = null;
                if (bold)
                {
                    f = new Font("微软雅黑", fontSize, FontStyle.Bold);
                }
                else
                {
                    f = new Font("微软雅黑", fontSize);
                }
                int addHeight = f.Height;
                //GetPagePrintSize(e, out float width, out float height);
                StringFormat format = new StringFormat();
                ////e.Graphics.DrawString(value, f, b, 100,0);
                ////format.LineAlignment = StringAlignment.Center;  // 更正： 垂直居中
                // 水平居中
                if (center)
                {
                    format.Alignment = StringAlignment.Center;
                }
                else
                {
                    format.Alignment = StringAlignment.Near;
                }
                string reportText = name;
                Type t = paramArray.GetType();
                PropertyInfo[] properties = t.GetProperties();
                foreach (PropertyInfo item in properties)
                {
                    string itemName = item.Name;
                    string itemValue = item.GetValue(paramArray, null).ToString();
                    if (itemName.Equals(value))
                    {
                        reportText = reportText + itemValue;
                    }
                }

                //判断是否需要换行
                if (!newLine)
                {
                    lengths = lengths - (int)oldAddHeight;
                }
                oldAddHeight = addHeight;
                //计算是否需要新的一页
                IsNeedNewPage(addHeight, ref lengths);
                //value = value + Environment.NewLine + value;
                graphics.DrawString(reportText, f, b, new Rectangle(x, y + lengths, (int)pageWidth, (int)pageHeight), format);
                lengths = lengths + addHeight + y;
            }
        }

        private void PrintBody<T>(XmlNode bodyNode, List<T> saletable, ref int lengths)
        {
            //设置字体颜色
            Brush b = new SolidBrush(Color.Black);
            XmlNode GridNode = bodyNode.SelectSingleNode("Grid");
            XmlElement gridElenment = GridNode as XmlElement;
            int x = Convert.ToInt32(gridElenment.GetAttribute("X"));
            int y = Convert.ToInt32(gridElenment.GetAttribute("Y"));
            bool headerBold = Convert.ToBoolean(gridElenment.GetAttribute("HeaderBold"));
            int columnFontSize = Convert.ToInt32(gridElenment.GetAttribute("ColumnFontSize"));
            var columnBold = gridElenment.GetAttribute("ColumnBold");
            int GridFillWidth = Convert.ToInt32(gridElenment.GetAttribute("FillWidth"));
            bool center = Convert.ToBoolean(gridElenment.GetAttribute("Center"));
            Font f = null;
            if (headerBold)
            {
                f = new Font("微软雅黑", columnFontSize, FontStyle.Bold);
            }
            else
            {
                f = new Font("微软雅黑", columnFontSize);
            }
            StringFormat format = new StringFormat();
            // 水平居中
            if (center)
            {
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;
            }
            else
            {
                format.Alignment = StringAlignment.Near;
                format.LineAlignment = StringAlignment.Center;
            }
            int addHeight = f.Height;
            Pen pen = new Pen(b, 1);
            //表格宽度
            int gridwidth = (int)(pageWidth * ((float)GridFillWidth / 100));
            DrawingGridHead(ref lengths, b, GridNode, x, y, f, format, addHeight, pen, gridwidth);
            DrawingGridBody(saletable, ref lengths, b, GridNode, x, y, f, format, addHeight, pen, gridwidth);
        }

        private void PrintFoot(XmlNode footNode, dynamic paramArray, ref int lengths)
        {
            Brush b = new SolidBrush(Color.Black);
            foreach (XmlNode textNode in footNode)
            {
                XmlElement textElement = textNode as XmlElement;
                /*<Text Name="付款方式：" Value="PayName" X="0" Y="10" FontSize="11" Bold="False" UnderLine="True" Center="False" NewLine="True"/>*/
                string name = textElement.GetAttribute("Name").ToString();
                string payName = textElement.GetAttribute("PayName").ToString();
                int x = Convert.ToInt32(textElement.GetAttribute("X"));
                int y = Convert.ToInt32(textElement.GetAttribute("Y"));
                int fontSize = Convert.ToInt32(textElement.GetAttribute("FontSize"));
                bool bold = Convert.ToBoolean(textElement.GetAttribute("Bold"));
                bool underLine = Convert.ToBoolean(textElement.GetAttribute("UnderLine"));
                bool center = Convert.ToBoolean(textElement.GetAttribute("Center"));
                bool newLine = Convert.ToBoolean(textElement.GetAttribute("NewLine"));
                string value = textElement.GetAttribute("Value").ToString();
                Font f = null;
                if (center && underLine)
                {
                    f = new Font("微软雅黑", fontSize, FontStyle.Bold | FontStyle.Underline);
                }
                else if (center && !underLine)
                {
                    f = new Font("微软雅黑", fontSize, FontStyle.Bold);
                }
                else if (!center && underLine)
                {
                    f = new Font("微软雅黑", fontSize, FontStyle.Underline);
                }
                else if (!center && !underLine)
                {
                    f = new Font("微软雅黑", fontSize);
                }
                int addHeight = f.Height;
                StringFormat format = new StringFormat();
                // 水平居中
                if (center)
                {
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Center;
                }
                else
                {
                    format.Alignment = StringAlignment.Near;
                    format.LineAlignment = StringAlignment.Center;
                }
                string reportText = name;
                Type t = paramArray.GetType();
                PropertyInfo[] properties = t.GetProperties();
                foreach (PropertyInfo item in properties)
                {
                    string itemName = item.Name;
                    string itemValue = item.GetValue(paramArray, null).ToString();
                    if (itemName.Equals(value))
                    {
                        reportText = reportText + itemValue;
                        continue;
                    }
                }
                //判断是否需要换行
                if (!newLine)
                {
                    lengths = lengths - (int)oldAddHeight;
                }
                oldAddHeight= addHeight;
                //计算是否需要新的一页
                IsNeedNewPage(addHeight, ref lengths);
                //value = value + Environment.NewLine + value;
                graphics.DrawString(reportText, f, b, new Rectangle(x, y + lengths, (int)pageWidth, addHeight), format);
                lengths = lengths + addHeight + y;
            }
        }

        /// <summary>
        /// 画表格体
        /// </summary>
        /// <param name="saletable"></param>
        /// <param name="lengths"></param>
        /// <param name="b"></param>
        /// <param name="gridNode"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="f"></param>
        /// <param name="format"></param>
        /// <param name="addHeight"></param>
        /// <param name="pen"></param>
        /// <param name="gridwidth"></param>
        /// <param name="widths"></param>
        private void DrawingGridBody<T>(List<T> saletable, ref int lengths, Brush b, XmlNode gridNode, int x, int y, Font f, StringFormat format,int addHeight, Pen pen, int gridwidth)
        {
            #region 画表体
            foreach (var product in saletable)
            {
                int widths = 0;
                int addHeightMax = f.Height;
                DrawingGridRow(ref lengths, b, gridNode, x, y, f, format, addHeight, pen, gridwidth, widths, product);
            }
            #endregion
        }

        /// <summary>
        /// 绘制表格行
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lengths"></param>
        /// <param name="b"></param>
        /// <param name="gridNode"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="f"></param>
        /// <param name="format"></param>
        /// <param name="addHeight"></param>
        /// <param name="pen"></param>
        /// <param name="gridwidth"></param>
        /// <param name="widths"></param>
        /// <param name="product"></param>
        /// <param name="addHeightMax"></param>
        private void DrawingGridRow<T>(ref int lengths, Brush b, XmlNode gridNode, int x, int y, Font f, StringFormat format,int addHeight, Pen pen, int gridwidth,int widths, T product)
        {
            int addHeightMax = 0;
            foreach (XmlNode columnNode in gridNode.ChildNodes)
            {
                XmlElement columnElement = columnNode as XmlElement;
                string Value = columnElement.GetAttribute("Value").ToString();
                int FillWidth = Convert.ToInt32(columnElement.GetAttribute("FillWidth"));
                string Textmsg = "";
                Type t = product.GetType();
                PropertyInfo[] properties = t.GetProperties();
                foreach (PropertyInfo item in properties)
                {
                    string itemName = item.Name;
                    string itemValue = item.GetValue(product, null).ToString();
                    if (itemName.Equals(Value))
                    {
                        Textmsg = itemValue;
                        continue;
                    }
                }
                SizeF sizeF = graphics.MeasureString(Textmsg, f);

                float rowWidth = (float)((float)gridwidth * ((float)FillWidth / 100.0));
                int rowCount = (int)Math.Ceiling(sizeF.Width / (rowWidth - f.Height));
                addHeight = f.Height;
                if ((addHeight * rowCount) > addHeightMax)
                {
                    addHeightMax = addHeight * rowCount + 2;
                }
                if (addHeightMax > pageHeight)
                {
                    addHeightMax = (int)pageHeight - 6;
                    ////需要打印的字符像素点长度
                    //int strLong = (int)Math.Floor((float)addHeightMax / (float)f.Height * (rowWidth - f.Height));
                    ////需要打印的字符长度
                    //strLong = (int)Math.Floor(Textmsg.Length * (strLong / sizeF.Width));
                    //Textmsg = Textmsg.Remove(strLong, Textmsg.Length - strLong);
                }
                //计算是否需要新的一页
                bool isnewPage = IsNeedNewPage(addHeightMax, ref lengths);
                if (isnewPage)
                {
                    graphics.DrawLine(pen, x, lengths + y, gridwidth + x, lengths + y);
                }
                widths += (int)rowWidth;
            }
            widths = 0;
            foreach (XmlNode columnNode in gridNode.ChildNodes)
            {
                XmlElement columnElement = columnNode as XmlElement;
                int FillWidth = Convert.ToInt32(columnElement.GetAttribute("FillWidth"));
                float rowWidth = (float)((float)gridwidth * ((float)FillWidth / 100.0));

                string Value = columnElement.GetAttribute("Value").ToString();

                string Textmsg = "";
                Type t = product.GetType();
                PropertyInfo[] properties = t.GetProperties();
                foreach (PropertyInfo item in properties)
                {
                    string itemName = item.Name;
                    string itemValue = item.GetValue(product, null).ToString();
                    if (itemName.Equals(Value))
                    {
                        Textmsg = itemValue;
                        continue;
                    }
                }
                SizeF sizeF = graphics.MeasureString(Textmsg, f);
                int rowCount = (int)Math.Ceiling(sizeF.Width / (rowWidth - f.Height));
                //addHeight = addHeight * rowCount+2;
                if ((addHeight * rowCount) > addHeightMax)
                {
                    addHeightMax = addHeight * rowCount + 2;
                }
                if (addHeightMax > pageHeight)
                {
                    addHeightMax = (int)pageHeight - 6;
                    //需要打印的字符像素点长度
                    int strLong = (int)Math.Floor((float)addHeightMax / (float)f.Height * (rowWidth - f.Height));
                    //需要打印的字符长度
                    strLong = (int)Math.Floor(Textmsg.Length * (strLong / sizeF.Width));
                    Textmsg = Textmsg.Remove(strLong, Textmsg.Length - strLong);
                }
                Rectangle dfs = new Rectangle(new Point(widths + x, lengths + y), new Size((int)Math.Ceiling(rowWidth), addHeightMax));

                graphics.DrawString(Textmsg, f, b, dfs, format);
                if (columnNode.Equals(gridNode.LastChild))
                {
                    //画数据最右边的竖线
                    graphics.DrawLine(pen, gridwidth + x, lengths + y, gridwidth + x, lengths + addHeightMax + y);
                }
                else
                {
                    graphics.DrawLine(pen, (float)Math.Ceiling(widths + rowWidth + x), lengths + y, (float)Math.Ceiling(widths + rowWidth + x), lengths + addHeightMax + y);
                }
                widths += (int)rowWidth;
            }

            //画最左边一根竖线
            graphics.DrawLine(pen, x, lengths + y, x, lengths + addHeightMax + y);
            //画每行底部横线
            graphics.DrawLine(pen, x, lengths + addHeightMax + y, gridwidth + x, lengths + addHeightMax + y);
            lengths += addHeightMax;
        }

        /// <summary>
        /// 画表头
        /// </summary>
        /// <param name="lengths"></param>
        /// <param name="b"></param>
        /// <param name="GridNode"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="f"></param>
        /// <param name="format"></param>
        /// <param name="addHeight"></param>
        /// <param name="pen"></param>
        /// <param name="Gridwidth"></param>
        /// <returns></returns>
        private int DrawingGridHead(ref int lengths, Brush b, XmlNode GridNode, int x, int y, Font f, StringFormat format, int addHeight, Pen pen, int Gridwidth)
        {
            #region 画表头
            //实时表格横坐标点位置
            int widths = 0;
            int addHeightMax = 0;
            foreach (XmlNode columnNode in GridNode.ChildNodes)
            {
                XmlElement columnElement = columnNode as XmlElement;
                string headerText = columnElement.GetAttribute("HeaderText").ToString();
                int FillWidth = Convert.ToInt32(columnElement.GetAttribute("FillWidth"));
                //graphics.DrawString(headerText, f, b, widths + x, lengths + y);
                float rowWidth = (float)((float)Gridwidth * ((float)FillWidth / 100.0));
                SizeF sizeF = graphics.MeasureString(headerText, f);
                
                int rowCount = (int)Math.Ceiling(sizeF.Width /rowWidth);
                addHeight = f.Height;
                if ((addHeight * rowCount) > addHeightMax)
                {
                    addHeightMax = addHeight * rowCount + 2;
                }
                if (addHeightMax > pageHeight)
                {
                    addHeightMax = (int)pageHeight - 6;
                }
                //计算是否需要新的一页
                bool isnewPage = IsNeedNewPage(addHeightMax, ref lengths);
                if (isnewPage)
                {
                    graphics.DrawLine(pen, x, lengths + y, Gridwidth + x, lengths + y);
                }
                widths += (int)rowWidth;
                //graphics.DrawString(headerText, f, b, new Rectangle(new Point(widths + x, lengths + y), new Size((int)rowWidth, addHeightMax)), format);
                if (columnNode.Equals(GridNode.LastChild))
                {
                    var dfd = Gridwidth + x;
                    //画数据最右边的竖线
                    //graphics.DrawLine(pen, Gridwidth + x, lengths + y, Gridwidth + x, lengths + addHeightMax + y);
                }
                else
                {
                    //画数据右边的竖线
                    //graphics.DrawLine(pen, (float)Math.Ceiling(widths + rowWidth + x), lengths + y, (float)Math.Ceiling(widths + rowWidth + x), lengths + addHeightMax + y);
                }
                widths += (int)rowWidth;
            }
            widths = 0;
            #region  新增
            foreach (XmlNode columnNode in GridNode.ChildNodes)
            {
                XmlElement columnElement = columnNode as XmlElement;
                int FillWidth = Convert.ToInt32(columnElement.GetAttribute("FillWidth"));
                string headerText = columnElement.GetAttribute("HeaderText").ToString();
                float rowWidth = (float)((float)Gridwidth * ((float)FillWidth / 100.0));

                //string Value = columnElement.GetAttribute("Value").ToString();

                
                SizeF sizeF = graphics.MeasureString(headerText, f);
                int rowCount = (int)Math.Ceiling(sizeF.Width / rowWidth);
                
                //addHeight = addHeight * rowCount+2;
                if ((addHeight * rowCount) > addHeightMax)
                {
                    addHeightMax = addHeight * rowCount + 2;
                }
                if (addHeightMax > pageHeight)
                {
                    addHeightMax = (int)pageHeight - 6;
                    //需要打印的字符像素点长度
                    int strLong = (int)Math.Floor((float)addHeightMax / (float)f.Height * (rowWidth - f.Height));
                    //需要打印的字符长度
                    strLong = (int)Math.Floor(headerText.Length * (strLong / sizeF.Width));
                    headerText = headerText.Remove(strLong, headerText.Length - strLong);
                }
                Rectangle dfs = new Rectangle(new Point(widths + x, lengths + y), new Size((int)Math.Ceiling(rowWidth), addHeightMax));

                graphics.DrawString(headerText, f, b, dfs, format);
                if (columnNode.Equals(GridNode.LastChild))
                {
                    //画数据最右边的竖线
                    graphics.DrawLine(pen, Gridwidth + x, lengths + y, Gridwidth + x, lengths + addHeightMax + y);
                }
                else
                {
                    graphics.DrawLine(pen, (float)Math.Ceiling(widths + rowWidth + x), lengths + y, (float)Math.Ceiling(widths + rowWidth + x), lengths + addHeightMax + y);
                }
                widths += (int)rowWidth;
            }
            #endregion

            //表头第一根横线
            graphics.DrawLine(pen, x, lengths + y, Gridwidth + x, lengths + y);
            //表头第二根横线
            graphics.DrawLine(pen, x, lengths + addHeightMax + y, Gridwidth + x, lengths + addHeightMax + y);
            //画表格最左边的竖线
            graphics.DrawLine(pen, x, lengths + y, x, lengths + addHeightMax + y);
            lengths += addHeightMax;
            #endregion
            return widths;
        }

        /// <summary>
        /// 获取打印区域的宽高
        /// </summary>
        /// <param name="bitmap"></param>
        private void GetPagePrintSize(Bitmap bitmap)
        {
            //有效打印区域的宽度
            pageWidth = bitmap.Width;
            //有效打印区域的高度
            pageHeight = bitmap.Height;
        }

        /// <summary>
        /// 判断是否需要换页
        /// </summary>
        /// <param name="addHeight">需要增加的高度</param>
        /// <param name="lenghts">现高度</param>
        /// <returns></returns>
        private bool IsNeedNewPage(int addHeight, ref int lenghts)
        {
            if ((lenghts + addHeight+5) > pageHeight)
            {
                Bitmap bitmap = new Bitmap((int)pageWidth, (int)pageHeight);
                
                bitmapList.Add(bitmap);
                this.graphics = Graphics.FromImage(bitmap);

                lenghts = 0;
                return true;
            }
            return false;
        }
    }
}